package com.hc.comm.utils;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.WritableRaster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

public class ImageHelper {

	/**
	 * 对图片进行放大（部分图片会变红）
	 * 
	 * @param srcPath
	 *            原始图片路径(绝对路径)
	 * @param newPath
	 *            放大后图片路径（绝对路径）
	 * @param times
	 *            放大倍数
	 * @return 是否放大成功
	 */

	public static boolean zoomInImage(String srcPath, String newPath,
			int maxWidth, int maxHeight) {
		BufferedImage bufferedImage = null;
		try {
			File of = new File(srcPath);
			if (of.canRead()) {
				bufferedImage = ImageIO.read(of);
			}
		} catch (IOException e) {
			// TODO: 打印日志
			return false;
		}

		if (bufferedImage != null) {
			bufferedImage = zoomInImage(bufferedImage, maxWidth, maxHeight);
			try {
				// TODO: 这个保存路径需要配置下子好一点
				ImageIO.write(bufferedImage, "JPG", new File(newPath)); // 保存修改后的图像,全部保存为JPG格式
			} catch (IOException e) {
				// TODO 打印错误信息
				return false;
			}
		}
		return true;
	}

	/**
	 *      * 对图片进行放大       *    * @param originalImage       *            原始图片
	 *      * @param maxWidth       *            目标宽度       * @param maxHeight
	 *      *            目标高度       * @return      
	 */
	public static BufferedImage zoomInImage(BufferedImage originalImage,
			int maxWidth, int maxHeight) {
		int times = 1; // 放大倍数 
		int width = originalImage.getWidth();
		int height = originalImage.getHeight();
		double sw = (maxWidth * 1.0) / (width * 1.0);
		double sh = (maxHeight * 1.0) / (height * 1.0);
		if (width > maxWidth && height > maxHeight) {
			return originalImage;
		} else if (width < maxWidth && height < maxHeight) {
			if (sw > sh) {
				times = (int) (sw + 0.8);
			} else {
				times = (int) (sh + 0.8);
			}
		} else if (width < maxWidth && height > maxHeight) {
			times = (int) (sw + 0.8);
		} else {
			times = (int) (sh + 0.8);
		}

		int lastW = times * width;
		int lastH = times * height;
		BufferedImage newImage = new BufferedImage(lastW, lastH,
				originalImage.getType());
		Graphics g = newImage.getGraphics();
		g.drawImage(originalImage, 0, 0, lastW, lastH, null);
		g.dispose();

		return newImage;
	}

	/**
	 * @Description: 对原始图片根据(x, y, width, height) = (0, 0, width,
	 *               height)进行缩放，生成BufferImage
	 * @param img
	 * @param width
	 *            预处理后图片的宽度
	 * @param height
	 *            预处理后图片高度
	 * @return
	 * @author
	 * @throws IOException
	 */
	public static BufferedImage scaleImage(Image img, int width, int height) {
		BufferedImage tag = new BufferedImage(width, height, 1);
		Graphics g = tag.getGraphics();
		g.drawImage(img.getScaledInstance(width, height, Image.SCALE_DEFAULT),
				0, 0, null);

		g.dispose();

		return tag;
	}

	public static boolean makeThumbnail(String srcPath, String newPath,
			int maxWidth, int maxHeight) {
		File file = new File(srcPath);

		return makeThumbnail(file, newPath, maxWidth, maxHeight);
	}

	public static boolean makeThumbnail(File srcPath, String newPath,
			int maxWidth, int maxHeight) {
		BufferedImage bufferedImage = null;
		try {
			if (srcPath != null && srcPath.canRead()) {
				bufferedImage = ImageIO.read(srcPath);
			}
		} catch (IOException e) {
			return false;
		}

		if (bufferedImage != null) {

			try {

				bufferedImage = scaleImage(bufferedImage, maxWidth, maxHeight);
				ImageIO.write(bufferedImage, "JPG", new File(newPath)); // 保存修改后的图像,全部保存为JPG格式
			} catch (IOException e) {
				// TODO 打印错误信息
				return false;
			}
		}
		return true;
	}

	/**
	 * 函 数 名: cut<br>
	 * 功能描述： <br>
	 * 创 建 人: 王国庆<br>
	 * 日 期: 2013-2-22<br>
	 * 输入输出:
	 * 
	 * @param image
	 *            内存中的图片 BufferedImage对象
	 * @param x
	 *            开始剪切的x坐标
	 * @param y
	 *            开始剪切的y坐标
	 * @param width
	 *            剪切的宽度
	 * @param height
	 *            剪切的高度
	 * @return<br>
	 */
	private static BufferedImage cutImage(BufferedImage image, int x, int y,
			int width, int height) {

		try {

			Iterator<ImageReader> it = ImageIO
					.getImageReadersByFormatName("jpg");

			ImageReader reader = it.next();
			// 获取图片流

			ByteArrayOutputStream output = new ByteArrayOutputStream();
			ImageIO.write(image, "jpg", output);

			ImageInputStream iis = ImageIO
					.createImageInputStream(new ByteArrayInputStream(output
							.toByteArray()));

			reader.setInput(iis, true);

			ImageReadParam param = reader.getDefaultReadParam();
			/*
			 * 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域，通过 Rectangle 对象
			 * 的左上顶点的坐标（x，y）、宽度和高度可以定义这个区域。
			 */
			Rectangle rect = new Rectangle(x, y, width, height);
			// 提供一个 BufferedImage，将其用作解码像素数据的目标。
			param.setSourceRegion(rect);

			BufferedImage bi = reader.read(0, param);

			output.close();
			output = null;
			iis.close();
			iis = null;

			// reader.dispose();
			reader = null;

			return bi;

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return null;
	}

	public static boolean cutAdjustCenterImage(File srcPath, String newPath,
			int maxWidth, int maxHeight) {
		BufferedImage bufferedImage = null;
		try {
			if (srcPath != null && srcPath.canRead()) {
				bufferedImage = ImageIO.read(srcPath);
			}
		} catch (IOException e) {
			return false;
		}

		if (bufferedImage != null) {
			int srcWidth = bufferedImage.getWidth();
			int srcHeight = bufferedImage.getHeight();

			if (srcWidth < maxWidth || srcHeight < maxHeight) {
				try {
					ImageIO.write(bufferedImage, "jpg", new File(newPath));
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

				return true;
			}

			int width = srcWidth;
			int height = srcHeight;

			double xFactor = ((srcWidth * 1.0) / (maxWidth * 1.0));
			double yFactor = ((srcHeight * 1.0) / (maxHeight * 1.0));

			if (xFactor > 1.5 || yFactor > 1.8) {

				double factor = xFactor < yFactor ? xFactor : yFactor;
				if (factor > 1.8) {
					factor = 1.8;
				}

				width = (int) (maxWidth * factor);
				height = (int) (maxHeight * factor);
				if (width > srcWidth) {
					width = srcWidth;
				}

				bufferedImage = scaleImage(bufferedImage, width, height);
			}

			try {

				// int index = newPath.lastIndexOf(".");
				// String testPath = newPath.substring(0, index)+"_test.jpg";

				// ImageIO.write(bufferedImage, "jpg", new File(testPath));

				bufferedImage = cutImage(bufferedImage, (width - maxWidth) / 2,
						(height - maxHeight) / 2, maxWidth, maxHeight);

				ImageIO.write(bufferedImage, "jpg", new File(newPath));
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

		return true;
	}

	/*
	 * 根据尺寸图片居中裁剪
	 */
	public static void cutCenterImage(String src, String dest, int w, int h)
			throws IOException {
		Iterator iterator = ImageIO.getImageReadersByFormatName("jpg");
		ImageReader reader = (ImageReader) iterator.next();
		InputStream in = new FileInputStream(src);
		ImageInputStream iis = ImageIO.createImageInputStream(in);
		reader.setInput(iis, true);
		ImageReadParam param = reader.getDefaultReadParam();
		int imageIndex = 0;
		Rectangle rect = new Rectangle((reader.getWidth(imageIndex) - w) / 2,
				(reader.getHeight(imageIndex) - h) / 2, w, h);
		param.setSourceRegion(rect);
		BufferedImage bi = reader.read(0, param);
		ImageIO.write(bi, "jpg", new File(dest));

	}

	public static void scaleCutImage(File oImage, int maxWidth, int maxHeight,
			String newImageName) {

		try {
			// scale
			ImageInputStream iis = ImageIO.createImageInputStream(oImage);

			Iterator<ImageReader> iterator = ImageIO.getImageReaders(iis);

			ImageReader reader = (ImageReader) iterator.next();

			reader.setInput(iis, true);

			BufferedImage source = reader.read(0);

			BufferedImage srcImage = new BufferedImage(maxWidth * 2,
					maxHeight * 2, source.getType());
			srcImage.getGraphics().drawImage(source, 0, 0, maxWidth * 2,
					maxHeight * 2, null);

			// cut
			int srcWidth = srcImage.getWidth(null);

			int srcHeight = srcImage.getHeight(null);

			if (srcWidth <= maxWidth && srcHeight <= maxHeight) {

				// saveImage(srcImage);
				ImageIO.write(srcImage, "jpeg", new File(newImageName));
				// ImageTools.writeJPEGImage(srcImage,"tj.jpg");
				return;

			}

			Iterator<ImageReader> it = ImageIO
					.getImageReadersByFormatName("jpeg");
			reader = it.next();

			// 获取图片流
			iis = ImageIO.createImageInputStream(oImage);

			/*
			 * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
			 * 此设置意味着包含在输入源中的图像将只按顺序读取，可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
			 */
			reader.setInput(iis, true);

			/*
			 * <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O
			 * 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的
			 * getDefaultReadParam 方法中返回 ImageReadParam 的实例。
			 */
			ImageReadParam param = reader.getDefaultReadParam();

			/*
			 * 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域，通过 Rectangle 对象
			 * 的左上顶点的坐标（x，y）、宽度和高度可以定义这个区域。
			 */
			if (maxWidth > srcWidth) {
				maxWidth = srcWidth;
			}

			if (maxHeight > srcHeight) {
				maxHeight = srcHeight;
			}

			int x = (srcWidth - maxWidth) / 2;
			int y = (srcHeight - maxHeight) / 2;
			int width = maxWidth;
			int height = maxHeight;

			Rectangle rect = new Rectangle(x, y, width, height);

			// 提供一个 BufferedImage，将其用作解码像素数据的目标。
			param.setSourceRegion(rect);

			/*
			 * 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象，并将 它作为一个完整的
			 * BufferedImage 返回。
			 */
			BufferedImage bi = reader.read(0, param);

			// 保存新图片
			ImageIO.write(bi, "jpeg", new File(newImageName));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void scaleImage(File oImage, int maxWidth, int maxHeight,
			String newImageName) {

		try {
			ImageInputStream iis = ImageIO.createImageInputStream(oImage);

			Iterator<ImageReader> iterator = ImageIO.getImageReaders(iis);

			ImageReader reader = (ImageReader) iterator.next();

			reader.setInput(iis, true);

			BufferedImage source = reader.read(0);

			BufferedImage tag = new BufferedImage(maxWidth, maxHeight,
					source.getType());
			tag.getGraphics()
					.drawImage(source, 0, 0, maxWidth, maxHeight, null);
			File file = new File(newImageName);
			ImageIO.write(tag, reader.getFormatName(), file);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static void cutImage(File oImage, int maxWidth, int maxHeight,
			String newImageName) {

		ImageInputStream iis = null;
		BufferedImage srcImage;

		try {
			srcImage = ImageIO.read(oImage);

			int srcWidth = srcImage.getWidth(null);

			int srcHeight = srcImage.getHeight(null);

			if (srcWidth <= maxWidth && srcHeight <= maxHeight) {

				// saveImage(srcImage);
				ImageIO.write(srcImage, "jpeg", new File(newImageName));
				// ImageTools.writeJPEGImage(srcImage,"tj.jpg");
				return;

			}

			Iterator<ImageReader> it = ImageIO
					.getImageReadersByFormatName("jpeg");
			ImageReader reader = it.next();

			// 获取图片流
			iis = ImageIO.createImageInputStream(oImage);

			/*
			 * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。
			 * 此设置意味着包含在输入源中的图像将只按顺序读取，可能允许 reader 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。
			 */
			reader.setInput(iis, true);

			/*
			 * <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O
			 * 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 将从其 ImageReader 实现的
			 * getDefaultReadParam 方法中返回 ImageReadParam 的实例。
			 */
			ImageReadParam param = reader.getDefaultReadParam();

			/*
			 * 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域，通过 Rectangle 对象
			 * 的左上顶点的坐标（x，y）、宽度和高度可以定义这个区域。
			 */
			if (maxWidth > srcWidth) {
				maxWidth = srcWidth;
			}

			if (maxHeight > srcHeight) {
				maxHeight = srcHeight;
			}

			int x = (srcWidth - maxWidth) / 2;
			int y = (srcHeight - maxHeight) / 2;
			int width = maxWidth;
			int height = maxHeight;

			Rectangle rect = new Rectangle(x, y, width, height);

			// 提供一个 BufferedImage，将其用作解码像素数据的目标。
			param.setSourceRegion(rect);

			/*
			 * 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象，并将 它作为一个完整的
			 * BufferedImage 返回。
			 */
			BufferedImage bi = reader.read(0, param);

			// 保存新图片
			ImageIO.write(bi, "jpeg", new File(newImageName));

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/***
	 * 功能：压缩图片变成小尺寸*** 02 参数1：oImage：原图；* 03 参数2：maxWidth：小尺寸宽度；* 04
	 * 参数3：maxHeight：小尺寸长度；* 05 参数4：newImageName：小尺寸图片存放的路径和新名字；* 06
	 * 参数5：fileType：小尺寸图片类型（png,gif,jpg...）
	 * 
	 * @throws IOException
	 ***/

	public static void compressImage(File oImage, int maxWidth, int maxHeight,
			String newImageName) {

		BufferedImage srcImage;
		try {
			srcImage = ImageIO.read(oImage);

			int srcWidth = srcImage.getWidth(null);

			int srcHeight = srcImage.getHeight(null);

			if (srcWidth <= maxWidth && srcHeight <= maxHeight) {

				// saveImage(srcImage);
				ImageIO.write(srcImage, "jpeg", new File(newImageName));
				// ImageTools.writeJPEGImage(srcImage,"tj.jpg");
				return;

			}

			Image scaledImage = srcImage.getScaledInstance(srcWidth, srcHeight,
					Image.SCALE_SMOOTH);

			double ratio = Math.min((double) maxWidth / srcWidth,
					(double) maxHeight / srcHeight);

			AffineTransformOp op = new AffineTransformOp(
					AffineTransform.getScaleInstance(ratio, ratio), null);

			scaledImage = op.filter(srcImage, null);

			// saveImage((BufferedImage) scaledImage, fileType, new
			// FileOutputStream(
			// newImageName));// 存盘
			// ImageIO.write(scaledImage, formatName, output);
			ImageIO.write((BufferedImage) scaledImage, "jpeg", new File(
					newImageName));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		;

	}

	public static void safeCompressImage(File oImage, int maxWidth,
			int maxHeight, String newImageName) {

		BufferedImage srcImage;
		try {
			srcImage = ImageIO.read(oImage);
			int srcWidth = srcImage.getWidth(null);

			int srcHeight = srcImage.getHeight(null);

			if (srcWidth <= maxWidth && srcHeight <= maxHeight) {

				// saveImage(srcImage);
				ImageIO.write(srcImage, "jpeg", new File(newImageName));
				// ImageTools.writeJPEGImage(srcImage,"tj.jpg");
				return;

			}

			Image scaledImage = srcImage.getScaledInstance(srcWidth, srcHeight,
					Image.SCALE_SMOOTH);

			double ratio = Math.min((double) maxWidth / srcWidth,
					(double) maxHeight / srcHeight);

			AffineTransformOp op = new AffineTransformOp(
					AffineTransform.getScaleInstance(ratio, ratio), null);

			scaledImage = op.filter(srcImage, null);

			// saveImage((BufferedImage) scaledImage, fileType, new
			// FileOutputStream(
			// newImageName));// 存盘
			// ImageIO.write(scaledImage, formatName, output);
			ImageIO.write((BufferedImage) scaledImage, "jpeg", new File(
					newImageName));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	/**
	 * 实现图像的等比缩放
	 * 
	 * @param source
	 * @param targetW
	 * @param targetH
	 * @return
	 */
	private static BufferedImage resize(BufferedImage source, int targetW,
			int targetH) {
		// targetW，targetH分别表示目标长和宽
		int type = source.getType();
		BufferedImage target = null;
		double sx = (double) targetW / source.getWidth();
		double sy = (double) targetH / source.getHeight();
		// 这里想实现在targetW，targetH范围内实现等比缩放。如果不需要等比缩放
		// 则将下面的if else语句注释即可
		if (sx < sy) {
			sx = sy;
			targetW = (int) (sx * source.getWidth());
		} else {
			sy = sx;
			targetH = (int) (sy * source.getHeight());
		}
		if (type == BufferedImage.TYPE_CUSTOM) { // handmade
			ColorModel cm = source.getColorModel();
			WritableRaster raster = cm.createCompatibleWritableRaster(targetW,
					targetH);
			boolean alphaPremultiplied = cm.isAlphaPremultiplied();
			target = new BufferedImage(cm, raster, alphaPremultiplied, null);
		} else
			target = new BufferedImage(targetW, targetH, type);
		Graphics2D g = target.createGraphics();
		// smoother than exlax:
		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
				RenderingHints.VALUE_INTERPOLATION_BICUBIC);
		g.drawRenderedImage(source, AffineTransform.getScaleInstance(sx, sy));
		g.dispose();
		return target;
	}

	/**
	 * 实现图像的等比缩放和缩放后的截取
	 * 
	 * @param inFilePath
	 *            要截取文件的路径
	 * @param outFilePath
	 *            截取后输出的路径
	 * @param width
	 *            要截取宽度
	 * @param hight
	 *            要截取的高度
	 * @param proportion
	 * @throws Exception
	 */

	public static void saveImageAsJpg(File srcPath, String outFilePath,
			int width, int hight) {

		InputStream in;
		try {
			in = new FileInputStream(srcPath);
			File saveFile = new File(outFilePath);

			BufferedImage srcImage = ImageIO.read(in);
			if (width > 0 || hight > 0) {
				// 原图的大小
				int sw = srcImage.getWidth();
				int sh = srcImage.getHeight();
				// 如果原图像的大小小于要缩放的图像大小，直接将要缩放的图像复制过去
				if (sw > width && sh > hight) {
					srcImage = resize(srcImage, width, hight);
				} else {
					String fileName = saveFile.getName();
					String formatName = fileName.substring(fileName
							.lastIndexOf('.') + 1);
					ImageIO.write(srcImage, formatName, saveFile);
					return;
				}
			}
			// 缩放后的图像的宽和高
			int w = srcImage.getWidth();
			int h = srcImage.getHeight();
			// 如果缩放后的图像和要求的图像宽度一样，就对缩放的图像的高度进行截取
			if (w == width) {
				// 计算X轴坐标
				int x = 0;
				int y = h / 2 - hight / 2;
				saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
			}
			// 否则如果是缩放后的图像的高度和要求的图像高度一样，就对缩放后的图像的宽度进行截取
			else if (h == hight) {
				// 计算X轴坐标
				int x = w / 2 - width / 2;
				int y = 0;
				saveSubImage(srcImage, new Rectangle(x, y, width, hight), saveFile);
			}
			
			in.close();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			MyLog.log("saveImageAsJpg()  e = " + e);
		}

	}

	/**
	 * 实现缩放后的截图
	 * 
	 * @param image
	 *            缩放后的图像
	 * @param subImageBounds
	 *            要截取的子图的范围
	 * @param subImageFile
	 *            要保存的文件
	 * @throws IOException
	 */
	private static void saveSubImage(BufferedImage image,
			Rectangle subImageBounds, File subImageFile) throws IOException {
		if (subImageBounds.x < 0 || subImageBounds.y < 0
				|| subImageBounds.width - subImageBounds.x > image.getWidth()
				|| subImageBounds.height - subImageBounds.y > image.getHeight()) {
			MyLog.log("saveSubImage()  Bad   subimage   bounds");
			return;
		}
		BufferedImage subImage = image.getSubimage(subImageBounds.x,
				subImageBounds.y, subImageBounds.width, subImageBounds.height);
		String fileName = subImageFile.getName();
		String formatName = fileName.substring(fileName.lastIndexOf('.') + 1);
		ImageIO.write(subImage, formatName, subImageFile);
	}
}
